除了昨天介紹的 useFormStatus
和 useActionState
以外,在 React 19 也推出一個 useOptimistic
的 Hook,用來處理樂觀更新。
樂觀更新是一種提升使用者體驗的方式。在發送請求的過程中,等待後端或 API 的回應可能需要一段時間。這時可以預設會回應成功,讓即時的反饋比較好,不會讓使用者感到延遲。這種方法通常適用於一些失敗影響較小且容易還原的操作,像是按讚、收藏,或是表單回應已送出的情況。但如果是會有重大影響的操作,例如金流處理等,就不建議使用樂觀更新。
基本結構:
const [optimisticState, addOptimistic] = useOptimistic(
state,
// updateFn
(currentState, optimisticValue) => {
// 合併當前狀態和樂觀值,並返回新的狀態
}
);
參數:
state
: 初始的狀態。updateFn(currentState, optimisticValue)
: 會是一個函數,用於生成樂觀狀態。它會接收兩個參數,並返回生成的樂觀狀態。此函數必須是純函數,不應該有任何副作用。currentState
是當前的狀態,optimisticValue
是傳遞的樂觀值,回傳值會是當前狀態和樂觀值合併而成。返回值:
optimisticState
: 生成的樂觀狀態。addOptimistic
: 當你有樂觀更新時要調用的調度函數。它接受一個參數 optimisticValue
,並使用當前的 state
和傳遞的 optimisticValue
來調用 updateFn
,來生成新的狀態。要注意的是, addOptimistic
的函數必須在 Transition 或 action 內使用,不然會出現錯誤。
form
的 action
範例 : 可以參考 React文件範例。
Transition 按讚範例 :
import { useOptimistic, useState } from "react";
import { fetchLike } from "./api";
export default function OptimisticLikeButton({ count, setCount }) {
const [optimisticLikes, setOptimisticLikes] = useOptimistic(
{ count: count },
(currentState, newLike) => ({ ...currentState, count: newLike })
);
const [isPending, startTransition] = useTransition();
const handleOptimistic = () => {
startTransition(async () => {
setOptimisticLikes(count + 1);
try {
const response = await fetchLike(count + 1);
setCount(response);
} catch (error) {
setOptimisticLikes(count);
console.error(error);
}
});
};
return (
<button onClick={handleOptimistic}>
👍 ({optimisticLikes?.count}) {isPending && <span>Updating</span>}
</button>
);
}
Transitions 是在 React 18 中引入的新概念,用來提高用戶畫面的響應速度,尤其是在性能較慢的設備上。使用 Transitions 可以有效降低某些 UI 更新的優先級,從而提升整體用戶體驗,讓應用程式的使用更加流暢。
在某些情況下,我們希望能立即對用戶的操作做出回應,例如用戶輸入內容或點擊按鈕等,這些行為應被視為比較緊急的更新。相對而言,當畫面需要切換到另一個畫面時,這些更新則被視為非緊急的。Transitions 的主要功能就是能夠有效區分這兩種情況,確保緊急更新不會受到非緊急更新的影響。
使用 Transitions 可以在重新渲染期間保持 UI 的響應性。例如,當用戶點擊一個選項時,如果用戶改變主意並選擇另一個選項,系統可以立即對該操作進行回應,而不需要等待第一個選項的內容渲染完成。
在 Transitions 中的狀態更新可以被其他狀態更新中斷。例如如果在 Transition 中更新了一個元件,但隨後有其他的輸入或點擊事件發生,React 將優先處理這些緊急更新,然後再重新開始執行 Transitions 的更新。
另外要注意的是如果有多個 Transitions 同時發生,React 會視為一個整體來進行更新,未來的版本可能會移除這個限制。
useTransition
是 React 18 中提供的 Hook,用來管理 Transitions。
使用範例:
import { useTransition } from "react";
function App() {
const [isPending, startTransition] = useTransition();
const handleTabChange = (nextTab) => {
startTransition(() => {
setTab(nextTab);
});
};
return (
<div>
<button onClick={() => handleTabChange("Tab1")}>Tab 1</button>
<button onClick={() => handleTabChange("Tab2")}>Tab 2</button>
{isPending && <span>Loading...</span>}
</div>
);
}
isPending
是一個 boolean 值,用來標記當前狀態是否正在處理。
startTransition
是用來標記某個狀態更新的函式。在無法使用 useTransition
的情況下使用。
const handleTabChange = (nextTab) => {
startTransition(() => {
setTab(nextTab);
});
};
useTransition
來確保 UI 在資料獲取期間依然保持響應。參考資料:
https://19.react.dev/reference/react/useOptimistic
https://19.react.dev/reference/react/useTransition
https://19.react.dev/reference/react/startTransition
https://react.dev/blog/2022/03/29/react-v1